﻿// CMakeProject1.cpp: 定义应用程序的入口点。
//

#include "CMakeProject1.h"

using namespace std;

#define MAX_PATH_LEN 256
#ifdef WIN32
#define ACCESS(fileName,accessMode) _access(fileName,accessMode)
#define MKDIR(path) _mkdir(path)
#else
#define ACCESS(fileName,accessMode) access(fileName,accessMode)
#define MKDIR(path) mkdir(path,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
#endif

// 读取bin文件
long long getBinSize(std::string path)
{
	long long size = 0;
	std::ifstream infile(path, std::ifstream::binary);

	infile.seekg(0, infile.end);
	size = infile.tellg();
	infile.seekg(0, infile.beg);

	infile.close();
	return size;
}

//网格三维坐标结构体
struct Point {
	Point() {};
	double x, y, z;
	Point(double x, double y, double z) : x(x), y(y), z(z) {}
};

//网格三维拓扑面结构体
struct Face {
	Face() {};
	long long p1, p2, p3, p4;
	Face(long long p1, long long p2, long long p3, long long p4) : p1(p1), p2(p2), p3(p3), p4(p4) {}
};

// 类型long转换为string
std::string longToString(long long num) {
	std::stringstream ss1;
	ss1 << num;  // or any other type
	std::string result = ss1.str();   // use .str() to get a string back
	return result;
}

// 使用字符分割
void strSplit(const string& str, const char split, vector<string>& res)
{
	if (str == "")		return;
	//在字符串末尾也加入分隔符，方便截取最后一段
	string strs = str + split;
	size_t pos = strs.find(split);

	// 若找不到内容则字符串搜索函数返回 npos
	while (pos != strs.npos)
	{
		string temp = strs.substr(0, pos);
		res.push_back(temp);
		//去掉已分割的字符串,在剩下的字符串中进行分割
		strs = strs.substr(pos + 1, strs.size());
		pos = strs.find(split);
	}
}
// 使用字符串分割
void strSplit(const string& str, const string& splits, vector<string>& res)
{
	if (str == "")		return;
	//在字符串末尾也加入分隔符，方便截取最后一段
	string strs = str + splits;
	size_t pos = strs.find(splits);
	int step = splits.size();

	// 若找不到内容则字符串搜索函数返回 npos
	while (pos != strs.npos)
	{
		string temp = strs.substr(0, pos);
		res.push_back(temp);
		//去掉已分割的字符串,在剩下的字符串中进行分割
		strs = strs.substr(pos + step, strs.size());
		pos = strs.find(splits);
	}
}

// 三维向量类
class Vector3D {
public:
	double x, y, z;

	Vector3D(double x = 0.0, double y = 0.0, double z = 0.0) : x(x), y(y), z(z) {}

	// 向量减法
	Vector3D operator-(const Vector3D& v) const {
		return Vector3D(x - v.x, y - v.y, z - v.z);
	}

	// 向量叉乘
	Vector3D cross(const Vector3D& v) const {
		return Vector3D(
			y * v.z - z * v.y,
			z * v.x - x * v.z,
			x * v.y - y * v.x
		);
	}

	// 向量点积
	double dot(const Vector3D& v) const {
		return x * v.x + y * v.y + z * v.z;
	}
};

// 计算六面体体积类
class Hexahedron {
private:
	std::vector<Vector3D> vertices;  // 8个顶点

public:
	Hexahedron(const std::vector<Vector3D>& verts) : vertices(verts) {
		if (vertices.size() != 8) {
			throw std::invalid_argument("Hexahedron must have exactly 8 vertices.");
		}
	}
	~Hexahedron() {
		vector<Vector3D>().swap(vertices);
		//vertices.clear();
	}

	// 计算体积
	double getVolume() const {
		// 选择一个顶点作为原点（例如第一个顶点）
		Vector3D& origin = *(new Vector3D(vertices[0]));

		// 从原点出发的三个向量
		Vector3D* vecA = new Vector3D(vertices[1] - origin);
		Vector3D* vecB = new Vector3D(vertices[2] - origin);
		Vector3D* vecC = new Vector3D(vertices[4] - origin);

		// 体积是这三个向量的混合积的绝对值
		Vector3D* crossAB = new Vector3D(vecA->cross(*vecB));
		double result = std::abs(crossAB->dot(*vecC));

		delete vecA;
		delete vecB;
		delete vecC;

		delete crossAB;
		delete& origin;

		return result;
	}
};

string decimalToString(long double value, int precision) {
	ostringstream oss;
	oss << std::fixed << std::setprecision(precision) << value;
	return oss.str();
}

void outPly(string baseFilePath = "",
	int meshCount = 0,
	map<long long, Point> pointsMap = {},
	long long pointCount = 0, 
	map<long long, Face> facesMap = {},
	long long faceCount = 0,
	long double iStart = 1.0,
	long double iEnd = 0.0) {

	string outfileName = baseFilePath + "_" + decimalToString((round(iStart * 10) / 10), 1) + "_" + decimalToString((round(iEnd * 10) / 10), 1) + "_" + to_string(meshCount) + ".ply";
	ofstream outfile(outfileName);

	outfile << "ply" << "\n";
	outfile << "format ascii 1.0" << "\n";
	outfile << "comment made by anonymous" << "\n";
	//cout << "comment this file is a cube" << endl;
	outfile << "comment  object: another cube" << "\n";
	outfile << "element vertex " << pointsMap.size() << "\n";

	outfile << "property float32 x" << "\n";
	outfile << "property float32 y" << "\n";
	outfile << "property float32 z" << "\n";
	//cout << "property red uint8" << endl;
	//cout << "property green uint8" << endl;
	//cout << "property blue uint8" << endl;
	outfile << "element face " << facesMap.size() << "\n";
	outfile << "property list uint8 int32 vertex_index" << "\n";
	outfile << "end_header" << "\n";

	for (long long i = 0; i < pointsMap.size(); i++) {
		//cout << pointsMap[i].x << " " << pointsMap[i].y << " " << pointsMap[i].z << endl;
		outfile << pointsMap[i].x << " " << pointsMap[i].y << " " << pointsMap[i].z << "\n";
	}

	for (long long i = 0; i < facesMap.size(); i++) {
		//cout << 4 << " " << facesMap[i].p1 << " " << facesMap[i].p2 << " " << facesMap[i].p3 << " " << facesMap[i].p4 << endl;
		outfile << 4 << " " << facesMap[i].p1 << " " << facesMap[i].p2 << " " << facesMap[i].p3 << " " << facesMap[i].p4 << "\n";
	}

	//清空数据，待重新装填
	pointsMap.clear();
	facesMap.clear();

	pointCount = 0;
	faceCount = 0;

	//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
	outfile.flush();
	outfile.close();

}

int64_t get_timestamp() {
	auto now = std::chrono::system_clock::now();
	auto duration = now.time_since_epoch();
	auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
	return millis;
}

// 从左到右依次判断文件夹是否存在,不存在就创建
// example: /home/root/mkdir/1/2/3/4/
// 注意:最后一个如果是文件夹的话,需要加上 '\' 或者 '/'
int32_t createDirectory(const std::string& directoryPath)
{
	uint32_t dirPathLen = directoryPath.length();
	if (dirPathLen > MAX_PATH_LEN)
	{
		return -1;
	}
	char tmpDirPath[MAX_PATH_LEN] = { 0 };
	for (uint32_t i = 0; i < dirPathLen; ++i)
	{
		tmpDirPath[i] = directoryPath[i];
		if (tmpDirPath[i] == '\\' || tmpDirPath[i] == '/')
		{
			if (ACCESS(tmpDirPath, 0) != 0)
			{
				int32_t ret = MKDIR(tmpDirPath);
				if (ret != 0)
				{
					return ret;
				}
			}
		}
	}
	return 0;
}

//是否输出网格点集和拓扑信息
bool OutputsMeshInformation = false;
//网格数据bin文件地址
string binFilePath = "F:\\data\\data3\\JD_Refined_BO3_geom.bin";
int iProgressBar = 0;

string filePath = "";
string fName = to_string(get_timestamp());

// 生成的网格bin文件的点集合文件
string filePathVertex = "";
// 体积34000及以上的网格
string baseFilePath = "";
// 体积400及以下的网格
string baseFilePath1 = "";

// 待赋值的变量
long long char_len, data_len;
char type, time1_type, name[128], unit[64], other[40];
double time1, Max, Min, Avg;
double* d_data = NULL;
int* i_data = NULL;

long long fileSize = 0;
long long binFileLen = 0;

set<int> countSet = {};
map<int, long long> countMap; // 创建一个map来存储每个数字及其出现的次数

//网格表面Z最大的点集合
map<string, string> poiMapXY;
map<string, string> poiMapXZ;
map<string, string> poiMapYZ;

map<string, string> poiMapXYnegative;
map<string, string> poiMapXZnegative;
map<string, string> poiMapYZnegative;

map<string, string> xyzRange;

const int sVolMin = 0;//小网格体积最小
const int sVolMax = 750;//小网格体积最大

const long long bVolMin = 1000;//大网格体积最小
const long long bVolMax = 999999999;//大网格体积最大

const long long outMeshCountChunk = 1 * 1000; //大网格分片打包输出的个数
const long long outMeshCountChunk1 = 1 * 1000;//小网格分片打包输出的个数

const int gridMultiples = 1;//网格粗化倍数参数
const int zAaxisStarts = 0;//网格切片Z轴的起始高度


void gridVtx() {
	//cout << "GRID_VTX" << ",";
			//输出txt格式的三维点集合文件
	ofstream fout1(filePathVertex);
	cout.rdbuf(fout1.rdbuf());

	//cout << "% x   y   z" << "\n";
	// 输出点集合到文件
	//cout << "处理三维点数据..." << endl;
	iProgressBar = 0;
	for (long long i = 0; i < data_len; i += 3) {
		//两个整数相除，结果会被截断为整数 小数部分被丢弃了
		// 正确的做法：至少有一个操作数是浮点数
		double result_double = (static_cast<double>(i) / data_len) * 100; // 将a转换为double类型，然后进行除法

		if (result_double && (iProgressBar < result_double)) {
			iProgressBar = result_double;
			// 更新进度条的当前位置
		}
		cout << d_data[i] << " " << d_data[i + 1] << " " << d_data[i + 2] << endl;
	}
	//关闭文件流
	fout1.close();

	/*
	//点序列，每三个值构成点，x、y、z，每8个点构成1个六面体网格
	//cout<<"处理投影点集合..."<<endl;
	iProgressBar = 0;
	for (long long i = 0; i < data_len; i += (3 * 8 * 1)) {

		//两个整数相除，结果会被截断为整数 小数部分被丢弃了
		// 正确的做法：至少有一个操作数是浮点数
		double result_double = (static_cast<double>(i) / data_len) * 100; // 将a转换为double类型，然后进行除法

		if (result_double && (iProgressBar < result_double)) {
			iProgressBar = result_double;
			// 更新进度条的当前位置
		}

		//三维坐标 x、y、z中的z值判断
		if (d_data[i + 2] > zAaxisStarts) {
			//cout << d_data[i] << " " << d_data[i + 1] << " " << d_data[i + 2] << "\n";
			//floor()和ceil()函数,还有round()函数
			long long x = floor(d_data[i]);
			//注意负数的处理
			long long y = floor(d_data[i + 1]);
			long long z = floor(d_data[i + 2]);

			if (floor(atof(xyzRange["xmin"].c_str())) > x || xyzRange["xmin"].size() == 0) {
				xyzRange["xmin"] = longToString(x);
			}
			else if (floor(atof(xyzRange["xmax"].c_str())) < x || xyzRange["xmax"].size() == 0) {
				xyzRange["xmax"] = longToString(x);
			}

			if (floor(atof(xyzRange["ymin"].c_str())) > y || xyzRange["ymin"].size() == 0) {
				xyzRange["ymin"] = longToString(y);
			}
			else if (floor(atof(xyzRange["ymax"].c_str())) < y || xyzRange["ymax"].size() == 0) {
				xyzRange["ymax"] = longToString(y);
			}

			if (floor(atof(xyzRange["zmin"].c_str())) > z || xyzRange["zmin"].size() == 0) {
				xyzRange["zmin"] = longToString(z);
			}
			else if (floor(atof(xyzRange["zmax"].c_str())) < z || xyzRange["zmax"].size() == 0) {
				xyzRange["zmax"] = longToString(z);
			}

			// 控制 xy 平面网格的疏密程度
			string xykey = longToString((x / 10) * 10) + "_" + longToString((y / 10) * 10);
			//cout << x << "-" << y<<"-" << z <<"_" << key << endl;
			if (poiMapXY.find(xykey) == poiMapXY.end()) {
				poiMapXY[xykey] = longToString((z / 1) * 1);
				//cout << poiMapXY[key] << endl;
				poiMapXYnegative[xykey] = longToString((z / 1) * 1);
			}
			else {

				//cout << poiMapXY[key] << endl;
				if (z > strtoll(poiMapXY[xykey].c_str(), NULL, 10)) {
					poiMapXY[xykey] = longToString((z / 1) * 1); // 如果数字已经在map中，且当前的z比他大，就重新赋值
				}
				else if (z < strtoll(poiMapXY[xykey].c_str(), NULL, 10)) {
					poiMapXYnegative[xykey] = longToString((z / 1) * 1);
				}
			}

			// 控制 xz 平面网格的疏密程度
			string xzkey = longToString((x / 10) * 10) + "_" + longToString((z / 10) * 10);
			//cout << x << "-" << y<<"-" << z <<"_" << key << endl;
			if (poiMapXZ.find(xzkey) == poiMapXZ.end()) {
				poiMapXZ[xzkey] = longToString((y / 1) * 1);
				//cout << poiMapXZ[xzkey] << endl;
				poiMapXZnegative[xzkey] = longToString((y / 1) * 1);
			}
			else {
				//cout << poiMapXZ[xzkey] << endl;
				if (y > strtoll(poiMapXZ[xzkey].c_str(), NULL, 10)) {
					poiMapXZ[xzkey] = longToString((y / 1) * 1); // 如果数字已经在map中，且当前的z比他大，就重新赋值
				}
				else if (y < strtoll(poiMapXZ[xzkey].c_str(), NULL, 10)) {
					poiMapXZnegative[xzkey] = longToString((y / 1) * 1);
				}
			}

			// 控制 yz 平面网格的疏密程度
			string yzkey = longToString((y / 10) * 10) + "_" + longToString((z / 10) * 10);
			//cout << x << "-" << y<<"-" << z <<"_" << key << endl;
			if (poiMapYZ.find(yzkey) == poiMapYZ.end()) {
				poiMapYZ[yzkey] = longToString((x / 1) * 1);
				//cout << poiMapYZ[yzkey] << endl;
				poiMapYZnegative[yzkey] = longToString((x / 1) * 1);
			}
			else {
				//cout << poiMapYZ[yzkey] << endl;
				if (x > strtoll(poiMapYZ[yzkey].c_str(), NULL, 10)) {
					poiMapYZ[yzkey] = longToString((x / 1) * 1); // 如果数字已经在map中，且当前的z比他大，就重新赋值
				}
				else if (x < strtoll(poiMapYZ[yzkey].c_str(), NULL, 10)) {
					poiMapYZnegative[yzkey] = longToString((x / 1) * 1);
				}
			}

		}


	}
	*/




	//cout << "\n";

	// 输出网格表面最大值的筛选结果
	/*
	cout << "% x   y   z" << "\n";
	for (const auto& pair : poiMapXY) {
		string s = pair.first;

		vector<string> tokens;
		string token;
		stringstream ss(s);
		while (getline(ss, token, '_')) {
			if (!token.empty()) {
				tokens.push_back(token);
			}				}
		if (tokens.size()==2) {
			cout << tokens[0] << " " << tokens[1] << " " << pair.second << "\n";
		}

	}*/

	//return 0;

	//网格尺寸信息

	//合并成一個網格文件輸出
	ofstream fout("outfile" + fName + "\\info_xyz_range.txt");
	cout.rdbuf(fout.rdbuf());

	for (const auto& pair : xyzRange) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}

	/*
	for (const auto& pair : poiMapXY) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}
	for (const auto& pair : poiMapXZ) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}
	for (const auto& pair : poiMapYZ) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}
	*/

	//return 0;
}

void meshNodeList(long double iStart = 1.0, long double iEnd = 0.0) {

	map<long long, Face> facesMap = {};
	map<long long, Point> pointsMap = {};

	atomic<long long> pointCount = 0;
	atomic<long long> faceCount = 0;

	atomic<long long> meshCount = 0;
	atomic<long long> outMeshCount = 0;


	map<long long, Face> facesMap1 = {};
	map<long long, Point> pointsMap1 = {};

	atomic<long long> pointCount1 = 0;
	atomic<long long> faceCount1 = 0;

	atomic<long long> meshCount1 = 0;
	atomic<long long> outMeshCount1 = 0;

	filebuf* pbuf;
	ifstream filestr;
	long long filesize;
	char* buffer;
	// 要读入整个文件，必须采用二进制打开 
	filestr.open(filePathVertex, ios::binary);
	// 获取filestr对应buffer对象的指针 
	pbuf = filestr.rdbuf();
	// 调用buffer对象方法获取文件大小
	filesize = pbuf->pubseekoff(0, ios::end, ios::in);
	pbuf->pubseekpos(0, ios::in);
	// 分配内存空间
	buffer = new char[filesize];
	// 获取文件内容
	pbuf->sgetn(buffer, filesize);
	filestr.close();
	// 输出到标准输出
	//cout.write(buffer, filesize);

	const char delims[] = "\n";
	char* result = NULL;
	char* ptr = NULL;
	result = strtok_s(buffer, delims, &ptr);
	vector<char*> res_split;//存储分割后的字符串
	while (result != NULL) {
		//cout<<result<<endl;
		res_split.push_back(result);
		result = strtok_s(NULL, delims, &ptr);
	}
	//cout << res_split.at(2) << endl;
	//delete[]buffer;

	//cout << "NODE_LIST" << ",";
	// 创建一个立方体
	//    v8----- v7
	//   /|      /|
	//  v5------v6|
	//  | |     | |
	//  | |v4---|-|v3
	//  |/      |/
	//  v1------v2
	/*
	//创建立方体的顶点
	vertices = [
		new THREE.Vector3(10, 10, 10), //v0
		new THREE.Vector3(-10, 10, 10), //v1
		new THREE.Vector3(-10, -10, 10), //v2
		new THREE.Vector3(10, -10, 10), //v3
		new THREE.Vector3(10, -10, -10), //v4
		new THREE.Vector3(10, 10, -10), //v5
		new THREE.Vector3(-10, 10, -10), //v6
		new THREE.Vector3(-10, -10, -10) //v7
	];*/
	//立方体的面
	/*int faceIndex[36] = {
		0, 1, 2,
		0, 2, 3,
		0, 3, 4,
		0, 4, 5,
		1, 6, 7,
		1, 7, 2,
		6, 5, 4,
		6, 4, 7,
		5, 6, 1,
		5, 1, 0,
		3, 2, 7,
		3, 7, 4
	};*/
	/**long long len = data_len - 160008;
	for (long long i = 0; i < len; i += 160000) {
		long long tempArr[8] = { d_data[i],d_data[i + 1],d_data[i + 2],d_data[i + 3],d_data[i + 4],d_data[i + 5],d_data[i + 6],d_data[i + 7] };
		for (int k = 0; k < 36; k += 3) {
			cout << 3 << " " << fixed << setprecision(5) << tempArr[faceIndex[k]] << " " << tempArr[faceIndex[k + 1]] << " " << tempArr[faceIndex[k + 2]] << " " << endl;
		}
	}*/

	int faceIndex[24] = {
		0,1,2,3,
		4,5,6,7,
		0,3,7,4,
		1,2,6,5,
		0,1,5,4,
		2,6,7,3
	};
	long long len = data_len - 8;
	//从下往上切片
	//for (long long i = 0; i < len; i += (8 * 1)) {

	//从上往下切片
	//cout<<"处理拓扑数据..."<<endl;
	iProgressBar = 0;
	long long step = (static_cast<long long>(8) * gridMultiples);
	long long start = (((len - step) * iStart) * 8) / 8;
	long long end = (((len - step) * iEnd) * 8) / 8;

	for (long long i = start; i > end; i -= step) {

		// 两个整数相除，结果会被截断为整数 小数部分被丢弃了
		// 正确的做法：至少有一个操作数是浮点数
		double result_double = 100.0 - (static_cast<double>(i - end) / static_cast<double>(start - end)) * 100.0; // 将a转换为double类型，然后进行除法

		if (result_double && (iProgressBar < result_double)) {
			iProgressBar = result_double;
			// 更新进度条的当前位置
		}

		long long tempArr[8] = { 0,0,0,0,0,0,0,0 };
		if (gridMultiples == 1) {
			tempArr[0] = d_data[i];
			tempArr[1] = d_data[i + 1];
			tempArr[2] = d_data[i + 2];
			tempArr[3] = d_data[i + 3];
			tempArr[4] = d_data[i + 4];
			tempArr[5] = d_data[i + 5];
			tempArr[6] = d_data[i + 6];
			tempArr[7] = d_data[i + 7];
		}
		else {
			tempArr[0] = d_data[i];
			tempArr[1] = d_data[i + 1 + 8 * gridMultiples];
			tempArr[2] = d_data[i + 2 + 8 * gridMultiples];
			tempArr[3] = d_data[i + 3 + 0 * gridMultiples];
			tempArr[4] = d_data[i + 4 + 0 * gridMultiples];
			tempArr[5] = d_data[i + 5 + 8 * gridMultiples];
			tempArr[6] = d_data[i + 6 + 8 * gridMultiples];
			tempArr[7] = d_data[i + 7 + 0 * gridMultiples];
		}

		// 定义8个顶点
		//vector<Vector3D> vertices = {
		//	{pointsMax[tempArr[0]].x, pointsMax[tempArr[0]].y, pointsMax[tempArr[0]].z},   // 顶点1
		//	{pointsMax[tempArr[1]].x, pointsMax[tempArr[1]].y, pointsMax[tempArr[1]].z},   // 顶点2
		//	{pointsMax[tempArr[2]].x, pointsMax[tempArr[2]].y, pointsMax[tempArr[2]].z},   // 顶点3
		//	{pointsMax[tempArr[3]].x, pointsMax[tempArr[3]].y, pointsMax[tempArr[3]].z},   // 顶点4
		//	{pointsMax[tempArr[4]].x, pointsMax[tempArr[4]].y, pointsMax[tempArr[4]].z},   // 顶点5
		//	{pointsMax[tempArr[5]].x, pointsMax[tempArr[5]].y, pointsMax[tempArr[5]].z},   // 顶点6
		//	{pointsMax[tempArr[6]].x, pointsMax[tempArr[6]].y, pointsMax[tempArr[6]].z},   // 顶点7
		//	{pointsMax[tempArr[7]].x, pointsMax[tempArr[7]].y, pointsMax[tempArr[7]].z}    // 顶点8
		//};

		vector<Vector3D> vertices = {};

		bool meshFaceTop = false;

		for (int l = 0; l < 8; l++) {

			string str = res_split.at(tempArr[l]);
			vector<string> strList;
			strSplit(str, ' ', strList);
			//cout << strList[0] << endl

			string x = strList[0];
			string y = strList[1];
			string z = strList[2];

			//vertices.push_back({ atof(x.c_str()),atof(y.c_str()),atof(z.c_str()) });
			//cout << x << "-" << y <<"-" << z << endl;
			// 控制分层切片的范围
			if (floor(atof(z.c_str())) > zAaxisStarts) {
				//cout << d_data[i] << " " << d_data[i + 1] << " " << d_data[i + 2] << "\n";
				//floor()和ceil()函数,还有round()函数
				long long x1 = floor(atof(x.c_str()));
				//注意负数的处理
				long long y1 = floor(atof(y.c_str()));
				long long z1 = floor(atof(z.c_str()));

				// 控制 xy 平面网格的疏密程度
				string xykey = longToString((x1 / 10) * 10) + "_" + longToString((y1 / 10) * 10);

				// 控制 xy 平面网格的疏密程度
				string xzkey = longToString((x1 / 10) * 10) + "_" + longToString((z1 / 10) * 10);

				// 控制 xy 平面网格的疏密程度
				string yzkey = longToString((y1 / 10) * 10) + "_" + longToString((z1 / 10) * 10);

				meshFaceTop = true;//网格全量輸出，跳过下面的抽壳筛选
				/*
				if (poiMapXY.find(xykey) == poiMapXY.end()) {
					//当前网格不在map里面
					//meshFaceTop = false;
				}
				else if (poiMapXZ.find(xzkey) == poiMapXZ.end()) {
					//当前网格不在map里面
					//meshFaceTop = false;
				}
				else if (poiMapYZ.find(yzkey) == poiMapYZ.end()) {
					//当前网格不在map里面
					//meshFaceTop = false;
				}
				else {
					//cout << xykey << endl;
					//当前网格在map里面 且z轴高度比之前的高
					if (z1 > strtoll(poiMapXY[xykey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (x1 > strtoll(poiMapYZ[yzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (y1 > strtoll(poiMapXZ[xzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (z1 < strtoll(poiMapXYnegative[xykey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (y1 < strtoll(poiMapXZnegative[xzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (x1 < strtoll(poiMapYZnegative[yzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
				}
				*/

			}
		}

		//控制模型的输出数据，可以打包所有网格一个ply文件，也可以每个小网格单独文件输出
		if (meshFaceTop) {
			for (int l = 0; l < 8; l++) {

				string str = res_split.at(tempArr[l]);
				vector<string> strList;
				strSplit(str, ' ', strList);
				//cout << strList[0] << endl
				string x = strList[0];
				string y = strList[1];
				string z = strList[2];

				vertices.push_back({ atof(x.c_str()),atof(y.c_str()),atof(z.c_str()) });
				//cout << x << "-" << y <<"-" << z << endl;

			}

			// 创建六面体对象 在堆上实例化 
			Hexahedron* myHexahedron = new Hexahedron(vertices);

			long long volume = round(myHexahedron->getVolume());

			// 输出体积
			//cout << "六面体体积Volume: " << volume << "，Type of a: " << typeid(volume).name() << endl;
			// 插入单个元素

			// 判断网格的体积是否大于400或者34000
			if (volume >= bVolMin && volume <= bVolMax) {
				// 根据采样参数 100 或 1000 处理输出网格数量
				if (!(meshCount % 1)) {

					//endl的目的是让用户可以在合理的时间点刷新文件。
					//打印\n不会(必然)刷新输出，而打印endl或flush则会。
					//如果您想要快速写入，并且在完成之前并不关心数据是否在那里，
					//那么使用\n完成所有的写入，不用担心(因为closing the file也会刷新流)，如果您仍然没有获得想要的性能，
					//那么可以使用fstream::read(char*, int) --它允许您以所需的任何大小的块读取数据(尝试更大的块)。

					for (int m = 0; m < 8; m++) {

						long long x = vertices[m].x;
						long long y = vertices[m].y;
						long long z = vertices[m].z;
						pointsMap.insert(pair<long long, Point>(pointCount, Point(x, y, z)));

						//outfile << x << " " << y << " " << z << "\n";

						//统计模型的所有点
						pointCount++;

						//cout << x << " " << y << " " << z << "\n";

					}

					for (int k = 0; k < 24; k += 4) {
						//cout << (pointIndex - 8) + faceIndex[k]<< " " << (pointIndex - 8) + faceIndex[k + 1]<< " " << (pointIndex - 8) + faceIndex[k + 2]<< " " << (pointIndex - 8) + faceIndex[k + 3] << endl;
						//cout << 4 << " " << fixed << setprecision(5) << tempArr[faceIndex[k]] << " " << tempArr[faceIndex[k + 1]] << " " << tempArr[faceIndex[k + 2]] << " " << tempArr[faceIndex[k + 3]] << endl;
						facesMap.insert(pair<long long, Face>(faceCount, Face((pointCount - 8) + faceIndex[k], (pointCount - 8) + faceIndex[k + 1], (pointCount - 8) + faceIndex[k + 2], (pointCount - 8) + faceIndex[k + 3])));

						//outfile << 4 << " " << faceIndex[k] << " " << faceIndex[k + 1] << " " << faceIndex[k + 2] << " " << faceIndex[k + 3] << "\n";

						//统计模型的所有面
						faceCount++;

					}
					//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
					//outfile.flush();
					//outfile.close();

					//每10000个网格打包输出
					if (!(outMeshCount % outMeshCountChunk) && outMeshCount != 0) {

						outPly(baseFilePath, meshCount, pointsMap, pointCount, facesMap, faceCount, iStart, iEnd);

						//清空数据，待重新装填
						pointsMap.clear();
						facesMap.clear();

						pointCount = 0;
						faceCount = 0;

						//return 0;
					}

					outMeshCount++;
				}

				//8个点构成一个网格，统计所有网格数量
				meshCount++;

			}

			// 判断网格的体积是否大于400或者34000
			if (volume >= sVolMin && volume <= sVolMax) {
				// 根据采样参数 100 或 1000 处理输出网格数量
				if (!(meshCount1 % 1)) {

					//endl的目的是让用户可以在合理的时间点刷新文件。
					//打印\n不会(必然)刷新输出，而打印endl或flush则会。
					//如果您想要快速写入，并且在完成之前并不关心数据是否在那里，
					//那么使用\n完成所有的写入，不用担心(因为closing the file也会刷新流)。
					//如果您仍然没有获得想要的性能，那么可以使用fstream::read(char*, int) --它允许您以所需的任何大小的块读取数据(尝试更大的块)。


					for (int m = 0; m < 8; m++) {

						long long x = vertices[m].x;
						long long y = vertices[m].y;
						long long z = vertices[m].z;
						pointsMap1.insert(pair<long long, Point>(pointCount1, Point(x, y, z)));

						//outfile << x << " " << y << " " << z << "\n";

						//统计模型的所有点
						pointCount1++;

						//cout << x << " " << y << " " << z << "\n";

					}

					for (int k = 0; k < 24; k += 4) {
						//cout << (pointIndex - 8) + faceIndex[k]<< " " << (pointIndex - 8) + faceIndex[k + 1]<< " " << (pointIndex - 8) + faceIndex[k + 2]<< " " << (pointIndex - 8) + faceIndex[k + 3] << endl;
						//cout << 4 << " " << fixed << setprecision(5) << tempArr[faceIndex[k]] << " " << tempArr[faceIndex[k + 1]] << " " << tempArr[faceIndex[k + 2]] << " " << tempArr[faceIndex[k + 3]] << endl;
						facesMap1.insert(pair<long long, Face>(faceCount1, Face((pointCount1 - 8) + faceIndex[k], (pointCount1 - 8) + faceIndex[k + 1], (pointCount1 - 8) + faceIndex[k + 2], (pointCount1 - 8) + faceIndex[k + 3])));

						//outfile << 4 << " " << faceIndex[k] << " " << faceIndex[k + 1] << " " << faceIndex[k + 2] << " " << faceIndex[k + 3] << "\n";

						//统计模型的所有面
						faceCount1++;

					}
					//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
					//outfile.flush();
					//outfile.close();

					//每10000个网格打包输出
					if (!(outMeshCount1 % outMeshCountChunk1) && outMeshCount1 != 0) {

						outPly(baseFilePath1, meshCount1, pointsMap1, pointCount1, facesMap1, faceCount1, iStart, iEnd);

						//清空数据，待重新装填
						pointsMap1.clear();
						facesMap1.clear();

						pointCount1 = 0;
						faceCount1 = 0;

						//return 0;
					}

					outMeshCount1++;
				}

				//8个点构成一个网格，统计所有网格数量
				meshCount1++;

			}

			countSet.insert(volume);
			countMap[volume]++; // 如果数字已经在map中，其对应的值增加1，否则插入新条目并初始化为1

			/*
			if ((!countMap.empty())&&countMap.size()>3){
				//动态调整最大最小网格体积筛选的阈值
				map<int, long long>::const_iterator itmax = extremeValueAnalysis(countMap, "value", "max");
				//cout << itmax->first << "_" << itmax->second << endl;

				//if (sVolMax < itmax->first) {
				//	sVolMax = itmax->first;
				//}

				//map<int, long long>::const_iterator itmin = extremeValueAnalysis(countMap, "value", "min");
				//cout << itmin->first << "_" << itmin->second << endl;
				//if (sVolMin > itmin->first) {
				//	sVolMin = itmin->first;
				//}

				vector< pair<int, long long> > v(countMap.begin(), countMap.end());//利用vector容器储存后再进行排序。
				sort(v.begin(), v.end(), cmp_value);//按 value 的从大到小排序的函数
				//for (vector< pair<int, long long> >::iterator it = v.begin(); it != v.end(); ++it){
				//	cout << it->first << " " << it->second << endl;
				//}
				auto it = v.begin();//获取第一个元素
				++it;//移动迭代器到第二个元素
				//cout << it->first << "_" << it->second << endl;//输出第二个元素
				//bVolMax = it->first;
			}
			*/
			vector<Vector3D>().swap(vertices);
			//vertices.clear();
			//memset((void*)&vertices, 0x0, sizeof(vertices));

			myHexahedron->~Hexahedron();
			//释放类实例的内存
			delete myHexahedron;
		}

		//网格体积分布
		//400 34000 2040000
		//400 800 1200 1600 2000 2400 2800 4000 
		//24000 32800 33200 33600 34000 34400 2040000

		//400 出现 1081253 次。
		//34000 出现 12786 次。

	}
	//cout << endl;

	//return 0;

	if (countSet.size() != 0 && countMap.size() != 0) {

		ofstream fout2("outfile" + fName + "\\info_count_mesh_type.txt");
		cout.rdbuf(fout2.rdbuf());

		// 使用迭代器遍历set
		for (set<int>::iterator it = countSet.begin(); it != countSet.end(); ++it) {
			cout << *it << " ";
		}

		cout << endl;

		// 输出每个数字及其出现的次数
		for (const auto& pair : countMap) {
			cout << "volume:" << pair.first << ",count:" << pair.second << endl;
		}

		//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
		fout2.close();

		if (pointsMap.size() != 0 && facesMap.size() != 0) {

			outPly(baseFilePath, meshCount, pointsMap, pointCount, facesMap, faceCount, iStart, iEnd);

			//清空数据，待重新装填
			pointsMap.clear();
			facesMap.clear();

			pointCount = 0;
			faceCount = 0;

		}



		if (pointsMap1.size() != 0 && facesMap1.size() != 0) {

			outPly(baseFilePath1, meshCount1, pointsMap1, pointCount1, facesMap1, faceCount1, iStart, iEnd);

			//清空数据，待重新装填
			pointsMap1.clear();
			facesMap1.clear();

			pointCount1 = 0;
			faceCount1 = 0;

			iProgressBar = 100;

			if (iProgressBar == 100) {
				cout << "任务结束。" << endl;
				cout << "任务已完成，可到文件夹 outfile" + fName + " 查阅。" << endl;
			}


		}


	}

}


int main()
{
	char filePathStr[500];
	bool taskType = false;
	cout << "请参照格式："+binFilePath+"，录入bin文件地址"<< endl;
	cin >> filePathStr;
	cout << "您录入的bin文件地址是： " << filePathStr << endl;
	if (filePathStr!="") {
		binFilePath = filePathStr;
	}

	cout << "获取模型信息，输入0；获取模型切片，输入1" << endl;
	cin >> taskType;

	if (taskType) {
		cout << "选择的任务是获取模型切片" << endl;
		OutputsMeshInformation = true;
	}
	else {
		cout << "选择的任务是获取模型信息" << endl;
		OutputsMeshInformation = false;
	}
	
	//模拟器输出的静态、动态网格bin文件
	//string filePath = "F:\\data\\data0\\SPE10_geom.bin";
	//打开文件 对话框，选择文件并显示文件的路径
	filePath = binFilePath;
	fileSize = getBinSize(filePath);
	binFileLen = fileSize;
	//fName = to_string(get_timestamp());

	// 生成的网格bin文件的点集合文件
	filePathVertex = "outfile" + fName + "\\vertex\\data.txt";
	// 体积34000及以上的网格
	baseFilePath = "outfile" + fName + "\\ply_batch\\b_";
	// 体积400及以下的网格
	baseFilePath1 = "outfile" + fName + "\\ply_batch\\s_";

	createDirectory("outfile" + fName + "\\vertex\\");
	createDirectory("outfile" + fName + "\\ply_batch\\");

	pair<string, string> p1 = make_pair("xmin", "");
	xyzRange.insert(p1);
	pair<string, string> p2 = make_pair("xmax", "");
	xyzRange.insert(p2);
	pair<string, string> p3 = make_pair("ymin", "");
	xyzRange.insert(p3);
	pair<string, string> p4 = make_pair("ymax", "");
	xyzRange.insert(p4);
	pair<string, string> p5 = make_pair("zmin", "");
	xyzRange.insert(p5);
	pair<string, string> p6 = make_pair("zmax", "");
	xyzRange.insert(p6);

	//生成的网格bin文件的点集合文件
	//filePathVertex = "G:\\hisim-3d\\test\\vertex\\data0-1.txt";
	// 体积34000及以上的网格
	//baseFilePath = "G:\\hisim-3d\\test\\outfile3\\ply_batch\\b_";
	// 体积400及以下的网格
	//baseFilePath1 = "G:\\hisim-3d\\test\\outfile3\\ply_batch\\s_";

	// 打开二进制文件
	ifstream fp(filePath, ios::binary);

	if (!fp.is_open()) {
		cerr << "无法打开文件" << endl;
		return 1;  // 返回错误代码
	}

	//合并成一個網格文件輸出
	ofstream fout("outfile" + fName + "\\info.txt");
	streambuf* pOld = std::cout.rdbuf(fout.rdbuf());

	cout << "读取bin格式网格文件 \"" << filePath << "\"" << endl;
	cout << "网格bin文件字节数：" << fileSize << " byte" << endl;

	//只输出网格数据概览信息
	if (!OutputsMeshInformation) {

		cout << "char_len" << ",";
		cout << "time" << ",";
		cout << "type" << ",";
		cout << "name" << ",";
		cout << "unit" << ",";
		cout << "data_len" << ",";
		cout << "time_type" << ",";
		cout << "d_data" << ",";
		cout << "i_data" << endl;

	}


	while (binFileLen > 8) {
		// 以下读取数组头
		fp.read((char*)&char_len, sizeof(long long));

		if (char_len) {
			binFileLen = binFileLen - char_len - 8;

		}
		else {
			binFileLen = 0;
		}

		fp.read((char*)&time1, sizeof(double));
		fp.read((char*)&type, sizeof(char));
		fp.read(name, 128);
		fp.read(unit, 64);
		fp.read((char*)&Max, sizeof(double));
		fp.read((char*)&Min, sizeof(double));
		fp.read((char*)&Avg, sizeof(double));
		fp.read(other, 40);
		time1_type = other[0];

		// 以下读取数组内容
		if (type == 'd') {
			//双精度数组
			data_len = (char_len - 265) / sizeof(double);
			d_data = new double[data_len];
			fp.read((char*)d_data, char_len - 265);
		}
		else if (type == 'i') {
			//整型数组
			data_len = (char_len - 265) / sizeof(int);
			i_data = new int[data_len];
			fp.read((char*)i_data, char_len - 265);
		}

		//只输出网格数据概览信息
		if (!OutputsMeshInformation) {
			cout << char_len << ",";
			cout << time1 << ",";
			cout << type << ",";
			cout << name << ",";
			cout << unit << ",";
			cout << data_len << ",";
			cout << time1_type << ",";
			cout << d_data << ",";
			cout << i_data << endl;

		}

		string str(name);
		str = name;

		//HiSim模拟器只输出有效网格的数据，排列顺序是I循环最快、J循环其次、K循环最慢，
		//如果有无效网格则跳过不输出，数组内容的长度等于有效网格数。
		//当模型包含加密区时，数据遵循的顺序是：粗网格在加密网格前，加密网格数据按加密区内部的I、J、K顺序放置，多个加密区依次放置。

		//网格几何数据是“Brick”格式，该格式包含“点集 + 拓扑”，可以描述结构或非结构的六面体单元，且单元顶点不需要是对齐的。Brick格式包含两个数组：
		//① 点集坐标，是顶点的(x, y, z)坐标，是double数组，长度等于“顶点数×3”，重合的点记为一个点；
		//② 网格顶点在点集中的编号，即每个网格由哪8个顶点组成，是整型数组，数组长度等于“有效基质网格数×8”，编号从1开始，8个顶点的顺序如图 1，顶点先排底面、再排顶面，面内逆时针排序。
		//HiSim模拟器输出的文件中，“点集坐标”名为“GRID_VTX”，网格顶点编号名为“NODE_LIST”

		//可以通过顶点共用的情况，判断网格的公共面、模型的外表面：
		//如果一个面的四个顶点既是网格A的顶点，也是网格B的顶点，则这个面是网格A、B的公共面，属于模型内部的面，反之这个面是模型的外表面。

		//网格几何数据“Brick”格式点集坐标信息 
		if (str == "GRID_VTX" && OutputsMeshInformation) {
			//int coreCount = get_core_count();
			thread thGridVtx = thread(gridVtx);
			thGridVtx.join();
		}


		//网格几何数据“Brick”格式顶点编号拓扑信息
		if (str == "NODE_LIST" && OutputsMeshInformation) {
			//int coreCount = get_core_count();
			//thread thMeshNodeList1 = thread(meshNodeList, 1.0, 0.0);
			//thread thMeshNodeList2 = thread(meshNodeList, 0.8, 0.6);
			//thread thMeshNodeList3 = thread(meshNodeList, 0.6, 0.4);
			//thread thMeshNodeList4 = thread(meshNodeList, 0.4, 0.2);
			//thread thMeshNodeList5 = thread(meshNodeList, 0.2, 0.0);
			//thMeshNodeList1.join();
			//thMeshNodeList2.join();
			//thMeshNodeList3.join();
			//thMeshNodeList4.join();
			//thMeshNodeList5.join();

			const int numThreads = 2; // 想要创建的线程数量
			std::thread threads[numThreads]; // 创建线程数组

			// 启动所有线程
			for (int i = 0; i < numThreads; ++i) {
				threads[i] = std::thread(meshNodeList, 1.0 - static_cast<long double> (i)*(1.0 / static_cast<long double> (numThreads)), 1.0 - (static_cast<long double> (i)+1)*(1.0 / static_cast<long double> (numThreads)));
				//threads[i] = std::thread(meshNodeList, 1.0, 0.0);
			}

			// 等待所有线程完成
			for (int i = 0; i < numThreads; ++i) {
				threads[i].join();
			}

		}



		if (type == 'd') {
			//双精度数组
			// 释放动态分配的数组内存
			delete[] d_data;
		}
		else if (type == 'i') {
			//整型数组
			// 释放动态分配的数组内存
			delete[] i_data;
		}


		if (fp.fail()) {  // 检查文件是否成功读取
			cerr << "错误读取文件\n";
			return 1;
		}



	}

	fp.close();

	if (!OutputsMeshInformation) {
		iProgressBar = 100;

		if (iProgressBar == 100) {
			fout.flush();
	        fout.close();
			cout<< "任务结束。" << endl;
			cout << "任务已完成，可到文件夹 outfile" + fName + " 查阅。" << endl;
		}
	}

	return 0;

}
